package com.example.mysql.学习笔记.高级.事务.锁.锁的分类.从粒度划分;

public class 表锁 {
}
/**
 * 1.表锁(Table Lock)
 * 该锁会锁定整张表，它是MySQL中最基本的锁策略
 * ，并不依赖于存储引擎(不管你是MySQL的什么存储引擎,对于表锁的策略都是一样的) ,
 * 并且表锁是开销最小的策略(因为粒度比较大)。
 * 由于表级锁-次会将整个表锁定，所以可以很好的避免死锁问题。
 * 当然，锁的粒度大所带来最大的负面影响就是出现锁资源争用的概率也会最高，
 * 导致并发率大打折扣。
 *
 * SHOW OPEN TABLES;//查看锁
 * show open tables where in_use>0;//>0表示有锁使用
 * lock tables 表名 write/read;//创造一个表的 写/读锁
 *
 * unlock tables;//释放锁
 *
 * 总结:
 * MyISAM在执行查询语句(SELECT) 前，
 * 会给涉及的所有表加读锁，在执行增删改操作前，会给涉及的表加写锁。
 * InnoDB存储引擎是不会为这个表添加表级别的读锁或者写锁的。
 * MySQL的表级锁有两种模式: (以MyISAM表进行操作的演示)
 * ●表共享读锁(Table Read Lock)
 * ●表独占写锁(Table Write Lock)
 *
 *
 *
 *
 */

/**
 * ② 意向锁(intention lock)
 * 在行锁添加一个x/s的锁的时候，会在上一级（表锁）添加一个意向x/s锁
 * 目的就是为了告诉表锁  我内部存在x/s的锁，不用一行一行遍历找是否有x/s的锁
 * InnoDB支持多粒度锁(multiple granularity locking) ，
 * 它允许行级锁与表级锁共存，而意向锁就是其中的一种表锁。
 * 1、意向锁的存在是为了协调行锁和表锁的关系，支持多粒度(表锁与行锁)的锁并存。
 * 2、意向锁是一种不与行级锁冲突表级锁，这一点非常重要。
 * 3、表明“某个事务正在某些行持有了锁或该事务准备去持有锁”
 * 意向锁分为两种:
 * ●意向共享锁: 事务有意向对表中的某些行加共享锁(S锁)
 * ●意向排他锁: 事务有意向对表中的某些行加排他锁(X锁)
 *  如果我们给某一行数据加上了排它锁,数据库会自动给更大一级的空间,
 *  比如数据页或数据表加上意向锁，
 *  告诉其他人这个数据页或数据表已经有人上过排它锁了,
 *  这样当其他人想要获取数据表排它锁的时候，
 *  只需要了解是否有人已经获取了这个数据表的意向排他锁即可。
 * 从上面的案例可以得到如下结论:
 * 1. InnoDB 支持多粒度锁，特定场景下，行级锁可以与表级锁共存。
 * 2.意向锁之间互不排斥，但除了IS与S(意向共享锁和共享锁)兼容外，
 *   意向锁会与共享锁/排他锁互斥。
 * 3. IX, IS是表级锁，不会和行级的X，S锁发生冲突。只会和表级的X，S发生冲突。
 * 4.意向锁在保证并发性的前提下，实现了行锁和表锁共存且满足事务隔离性的要求。
 *
 */

/**
 * ③自增锁(AUTO-INC锁)
 * 在使用MySQL过程中，我们可以为表的某个列添加 AUTO INCREMENT属性。
 * 所有插入数据的方式总共分为三类，分别是
 * 1.“Simple inserts”(简单插入)
 *   可以预先确定要插入的行数(当语句被初始处理时)的语句。
 *   包括没有嵌套子查询的单行和多行 INSERT.. .VALUES()和REPLACE语句。
 * 2.“Bulk inserts”(批量插入)
 *   事先不知道要插入的行数(和所需自动递增值的数量)的语句。
 *   比如INSERT ... SELECT , REPLACE ... SELECT和LOAD DATA 语句,
 *   但不包括纯INSERT。InnoDB在每处理一行，为AUTO_INCREMENT列分配一个新值。
 * 3.“Mixed-mode inserts”(混合模式插入)
 *   这些是“Simple inserts'语句但是指定部分新行的自动递增值。
 *   例如INSERT INTO teacher (id, name) VALUES
 *   (1,'a')， (NULL,'b')， (5,'c')， (NULL,'d');
 *   只是指定了部分id的值。另--种类型的“混合模式插入”是
 *   INSERT ... ON DUPLICATE KEY UPDATE 。
 *
 * 对于上面数据插入的案例，MySQL中采用了自增锁的方式来实现，
 * AUTO-INC锁是当向使用含有 AUTO_INCREMENT 列的表中插入数据时
 * 需要获取的一种特殊的表级锁，在执行插入语句时就在表级别加一个AUTO-INC锁，
 * 然后为每条待插入记录的AUTO_INCREMENT修饰的列分配递增的值，
 * 在该语句执行结束后，再把AUTO-INC锁释放掉。
 * -个事务在持有AUTO-INC锁的过程中，其他事务的插入语句都要被阻塞，
 * 可以保证一个语句中分配的递增值 是连续的。
 * 也正因为此，其并发性显然并不高，
 * 当我们向-个有AUTO_INCREMENT关键字的主键插入值的时候，
 * 每条语句都要对这个表锁进行竞争，这样的并发潜力其实是很低下的，
 * 所以Innodb通过innodb_autoinc_lock_mode
 * 的不同取值来提供不同的锁定机制，来显著提高SQL语句的可伸缩性和性能。
 *
 * innodb_autoinc_lock_mode有三种取值，分别对应与不同锁定模式:
 * (1) innodb_autoinc_lock_mode = 0("传统” 锁定模式)
 * 在此锁定模式下，""所有类型的insert语句都会获得一个特殊的表级AUTO-INC锁，""
 * 用于插入具有AUTO_INCREMENT列的表。即每当执行insert的时候，都会得到一个表级锁(AUTO-INC锁)，使得语
 * 句中生成的auto_increment为顺序， 且在binlog中重放的时候,可以保证master与slave中数据的auto_increment是
 * 相同的。因为是表级锁，当在同一时间多个事务中执行insert的时候，对于AUTO-INC锁的争夺会限制并发能力。
 * (2) innodb_autoinc_lock_mode = 1("连续" 锁定模式)
 * 在MySQL 8.0之前，连续锁定模式是默认的。
 * 在这个模式下,“bulk inserts"仍然使用AUTO-INC表级锁，并保持到语句结束。
 * 这适用于所有INSERT .. SELECT, REPLACE .. SELECT和LOAD DATA语句。
 * 同--时刻只有一个语句可以持有AUTO-INC锁。
 * 对于“simple inserts" (要指入的行数事先已知)，则通过在mutex (轻量锁)的控制下获得所需数量的自动递增
 * 值来避免表级AUTO-INC锁，它只在分配过程的持续时间内保持， 而不是直到语句完成。
 * 不使用表级AUTO-INC锁，除非AUTO-INC锁由另一个事务保持。
 * 如果另一个事务保持AUTO-INC锁， 则"“Simple inserts’等待AUTO-INC锁，
 * 如同它是一个“bulk inserts"。
 * (3) innodb_autoinc_lock_mode = 2("交错“锁定模式) 保证了递增 但不连续，但是提高了并发性
 * 在此锁定模式下，自动递增值保证在所有并发执行的所有类型的insert语句中是唯一且单调递增的。
 * 但是，由于多个语句可以同时生成数字(即，跨语句交叉编号)
 * 为任何给定语句插入的行生成的值    可能不是连续的。
 *
 *
 *
 */

/**
 * ④元数据锁(MDL锁)
 * MySQL5.5引入了meta data lock,简称MDL锁,属于表锁范畴。
 * MDL 的作用是，保证读写的正确性。
 * 比如，如果一个查询正在遍历一个表中的数据，
 * 而执行期间另一个线程对这个表结构做变更，增加了一列，
 * 那么查询线程拿到的结果跟表结构对不上，肯定是不行的。
 *
 * 因此，当对一个表做增删改查操作的时候，加MDL读锁;
 * 当要对表做结构变更操作的时候，加MDL写锁。
 * 读锁之间不互斥，因此你可以有多个线程同时对一张表增删改查。
 * 读写锁之间、写锁之间是互斥的，用来保证变更表结构操作的安全性，
 * 解决了DML和DDL操作之间的一致性问题。
 * 不需要显式使用,在访问一个表的时候会被自动加上。
 *
 * 缺点：当某一个事务加了MDL读锁时 来了一个MDL写锁  ，MDL写锁会堵塞
 *     但是如果再来一个MDL读锁 按理说可以和第一个MDL读锁共享，但是不能
 *
 *
 *
 *
 */